/*
 *  Copyright (C) 2010 Zubanov Dmitry
 * 
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 * 
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
/**
 *
 * @author Zubanov Dmitry aka javadimon, zubanov@gmail.com
 * Omsk, Russia, created 29.05.2010
 * (C) Copyright by Zubanov Dmitry
 */
package org.jssdb.core.filesystem;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.CRC32;
import java.util.zip.CheckedInputStream;
import org.jssdb.core.net.ReplicationServer;
import org.jssdb.core.utils.FileSeparator;

public class FilesListInfo implements Serializable {

    private static FilesListInfo self = null;
    private int port;
    private String host;
    private ArrayList<FileObjectInfo> listInfo = new ArrayList();
    private static final Object sync = new Object();
    private static final Logger logger = Logger.getLogger(FilesListInfo.class.getName());

    private FilesListInfo() {
        port = ReplicationServer.getInstance().getPort();
        host = ReplicationServer.getInstance().getHost();
    }

    public ArrayList<FileObjectInfo> getFilesListInfo() {
        return listInfo;
    }

    public String getHost() {
        return host;
    }

    public int getPort() {
        return port;
    }

    public void addNewFileInfo(String fullPathToFile) {
        File f = new File(fullPathToFile);
        addFileInfo(f);

    }

    public void modifyFileInfo(String fullPathToFile) {
        if (fullPathToFile == null || fullPathToFile.equals("")) {
            return;
        }

        String arr[] = fullPathToFile.split(FileSeparator.getInstance().separator);
        if (arr.length < 2) {
            return;
        }

        synchronized (sync) {
            for (FileObjectInfo fileObjectInfo : listInfo) {
                if (fileObjectInfo.getClassName().equals(arr[arr.length - 2])
                        && fileObjectInfo.getFileName().equals(arr[arr.length - 1])) {
                    File f = new File(fullPathToFile);
                    try {
                        fileObjectInfo.setCRC32(getCRC32(f));
                        fileObjectInfo.setLastModified(f.lastModified());
                    } catch (Exception e) {
                        logger.log(Level.WARNING, "can't get CRC32", e);
                    }
                }
            }
        }
    }

    public void deleteFileInfo(String className, long id) {
        synchronized (sync) {
            for (FileObjectInfo fileObjectInfo : listInfo) {
                if (fileObjectInfo.getClassName().equals(className)
                        && fileObjectInfo.getFileName().equals("" + id)) {
                    listInfo.remove(fileObjectInfo);
                    break;
                }
            }
        }
    }

    public void addDir(File file) {
        File files[] = file.listFiles();
        for (File f : files) {
            if (f.isDirectory()) {
                continue;
            }

            addFileInfo(f);
        }
    }

    private void addFileInfo(File f) {
        try {
            String arr[] = f.getAbsolutePath().split(FileSeparator.getInstance().separator);
            synchronized (sync) {
                listInfo.add(new FileObjectInfo(arr[arr.length - 2],
                        arr[arr.length - 1], f.lastModified(),
                        getCRC32(f)));
            }

        } catch (Exception e) {
            logger.log(Level.SEVERE, null, e);
        }
    }

    private long getCRC32(File f) throws Exception {
        long crc = -1;
        CheckedInputStream cis = null;
        try {
            // Computer CRC32 checksum
            if (!f.isFile()) {
                return crc;
            }
            cis = new CheckedInputStream(new FileInputStream(f), new CRC32());

        } catch (FileNotFoundException e) {
            logger.log(Level.WARNING, "" + f, e);
        }

        byte[] buf = new byte[128];
        while (cis.read(buf) >= 0) {
        }

        crc = cis.getChecksum().getValue();

        cis.close();

        return crc;
    }

    public static FilesListInfo getInstance() {
        if (self == null) {
            self = new FilesListInfo();
        }

        return self;
    }

    @Override
    public String toString() {
        return MessageFormat.format("Host {0}, Port {1}, File size count {2}",
                new Object[]{host, port, listInfo.size()});
    }
}
